#include "litebalancemutex.h"

namespace {
	static std::thread::id g_nonThreadId = std::thread::id();
}

LiteBalanceMutex::LiteBalanceMutex(int spinTimes)
	: m_spinCount(spinTimes)
{

}

void LiteBalanceMutex::lock()
{
	//��ȡ��ǰ�߳�id
	std::thread::id curThrId = std::this_thread::get_id();
	//��������
	std::atomic<int> currCount(m_spinCount);
	//����ʧ�ܻ�ȡ��ʧ��������

	if (_checkLockThread(curThrId))
	{
		return;
	}

START_GET_LOCK:
	{
		while (!m_currentThreadId.compare_exchange_strong(g_nonThreadId, curThrId, std::memory_order_acquire))
		{
			if (!currCount.fetch_sub(1, std::memory_order_acquire))
				break;
			else
				std::this_thread::yield();
		}
		//����ʧ�ܻ�ȡ��ʧ��������
		if (!_checkLockThread(curThrId))
		{
			std::unique_lock<std::mutex> locker(m_muetex);
			m_condition.wait(locker, [&](){
				return !isLock();
			});
			locker.unlock();
			//�����ó������»�ȡ��
			goto START_GET_LOCK;
		}
	}
}

void LiteBalanceMutex::unlock()
{
	std::thread::id curThrId = std::this_thread::get_id();

	while (m_currentThreadId.compare_exchange_strong(curThrId, g_nonThreadId, std::memory_order_acquire));

	//���ͷź������������ڸ������߳�
	m_condition.notify_all();
}

bool LiteBalanceMutex::isLock() const
{
	return m_currentThreadId.load(std::memory_order_acquire) != g_nonThreadId;
}

bool LiteBalanceMutex::_checkLockThread(const std::thread::id& threadId)
{
	return m_currentThreadId.load(std::memory_order_acquire) == threadId;
}